package com.lzj.server.utils;

import java.util.Arrays;

/**
 * @author Lzj
 * 向量工具类
 */
public class VectorUtils {
    /**
     * normalize(double[] vector):
     * 作用： 对向量进行 L2 范数归一化，使其长度为1。
     * 实现： 计算向量各分量平方和的平方根（即向量的L2范数或模长），然后将每个分量除以这个模长。
     * 边缘情况： if (norm == 0) return vector; 处理了零向量的情况，避免了除以零的错误，保持了鲁棒性。
     * 重要性： 在向量搜索中，通常要求所有参与比较的向量（包括视频向量和用户兴趣向量）都是归一化的。这使得距离度量（如欧氏距离或余弦相似度）能够更纯粹地反映向量的方向（语义），而不是其长度。
     *
     * @param vector 向量
     * @return 归一化后的向量
     */
    public static double[] normalize(double[] vector) {
        double norm = Math.sqrt(Arrays.stream(vector).map(x -> x * x).sum());
        if (norm == 0) return vector;
        return Arrays.stream(vector).map(x -> x / norm).toArray();
    }

    /**
     * emaMerge(double[] oldVec, double[] newVec, double alpha):
     * 作用： 实现指数移动平均 (EMA) 算法，用于增量更新用户兴趣向量。
     * 公式： result[i] = alpha * newVec[i] + (1 - alpha) * oldVec[i]
     * alpha：平滑因子，0 < alpha <= 1。
     * alpha 接近1：新向量对结果的影响更大，更新更快，更能捕捉近期兴趣。
     * alpha 接近0：旧向量保留更多信息，更新平缓，更稳定。
     * newVec：代表当前新发生行为对应的视频向量（注意：在实际应用中，newVec 应该是经过行为权重加权后的视频向量）。
     * oldVec：用户当前的兴趣向量。
     *
     * @return 增量更新后的用户兴趣向量
     */
    public static double[] emaMerge(double[] oldVec, double[] newVec, double alpha) {
        double[] result = new double[oldVec.length];
        for (int i = 0; i < oldVec.length; i++) {
            result[i] = alpha * newVec[i] + (1 - alpha) * oldVec[i];
        }
        return result;
    }
}

